package avicit.bdp.dcs.stream.service;

import avicit.bdp.common.base.BaseService;
import avicit.bdp.common.utils.BdpLogUtil;
import avicit.bdp.common.utils.CheckParaUtils;
import avicit.bdp.core.constant.Constants;
import avicit.bdp.core.util.json.JSONUtils;
import avicit.bdp.dcs.job.dto.JobDTO;
import avicit.bdp.dcs.stream.dao.MsgTemplateDao;
import avicit.bdp.dcs.stream.dto.MeasureParaDto;
import avicit.bdp.dcs.stream.dto.MsgTemplateDto;
import avicit.bdp.dcs.utils.DcsConstants;
import avicit.bdp.dcs.utils.MsgTemplateExcelUtils;
import avicit.platform6.api.system.ConvertColumnClient;
import avicit.platform6.commons.utils.BusinessUtil;
import avicit.platform6.commons.utils.ComUtil;
import avicit.platform6.core.context.ThreadContextHelper;
import avicit.platform6.core.exception.BusinessException;
import avicit.platform6.core.properties.PlatformConstant;
import avicit.platform6.core.rest.msg.QueryRespBean;
import com.alibaba.fastjson2.JSONObject;
import com.github.pagehelper.Page;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.*;

/**
 * @金航数码科技有限责任公司
 * @作者：developer
 * @邮箱：developer@avic-digital.com
 * @创建时间：2020-10-16
 * @类说明：MsgTemplateService
 * @修改记录：
 * @注意事项：
 * @主要功能：消息模板Service接口，包括消息模板、模板参数、模板文件处理功能
 */
@Service
@Transactional
public class MsgTemplateService extends BaseService<MsgTemplateDao, MsgTemplateDto> {
  private static final Logger logger = LoggerFactory.getLogger(MsgTemplateService.class);

  @Autowired private MsgTemplateDao msgTemplateDao;
  @Autowired private ConvertColumnClient convertColumnClient;

  /**
   * 新增消息模板
   *
   * @param msgTemplateDto
   * @return
   * @throws Exception
   */
  public String createMsgTemplate(MsgTemplateDto msgTemplateDto) {
    // step1:参数合法性检查
    CheckParaUtils.checkObjectValidity(msgTemplateDto, logger, "参数为null");
    CheckParaUtils.checkStringValidity(msgTemplateDto.getDeviceId(), logger, "参数[deviceId]不能为空");
    CheckParaUtils.checkStringValidity(
        msgTemplateDto.getDeviceName(), logger, "参数[deviceName]不能为空");

    // step2:生成主键ID
    String id = ComUtil.getId();
    msgTemplateDto.setId(id);

    // step3:查询消息模板deviceId是否重复
    if (isDeviceIdRepeated(msgTemplateDto.getDeviceId())) {
      CheckParaUtils.printLogAndThrowException(
          logger,
          String.format(
              "消息模板[%s,%s]已存在", msgTemplateDto.getDeviceName(), msgTemplateDto.getDeviceId()));
    }

    // 记录日志
    BdpLogUtil.log4Insert(msgTemplateDto);

    // step4:持久化
    insert(msgTemplateDto);

    return id;
  }

  /**
   * 修改消息模板
   *
   * @param msgTemplateDto
   * @return
   * @throws Exception
   */
  public void updateMsgTemplate(MsgTemplateDto msgTemplateDto) {
    // step1:参数合法性检查
    CheckParaUtils.checkObjectValidity(msgTemplateDto, logger, "参数为null");
    CheckParaUtils.checkStringValidity(msgTemplateDto.getId(), logger, "参数[id]不能为空");
    CheckParaUtils.checkStringValidity(msgTemplateDto.getDeviceId(), logger, "参数[deviceId]不能为空");
    CheckParaUtils.checkStringValidity(
        msgTemplateDto.getDeviceName(), logger, "参数[deviceName]不能为空");

    // step2:查询消息模板是否存在(根据主键ID)
    MsgTemplateDto msgTemplateDtoQuery = selectByPrimaryKey(msgTemplateDto.getId());
    CheckParaUtils.checkObjectValidity(
        msgTemplateDtoQuery, logger, String.format("消息模板[%s]不存在", msgTemplateDto.getId()));

    // step3:检查待修改的模板templateId是否与其他消息模板重复（不包括自身）
    MsgTemplateDto retMsgTemplate =
        this.mapper.getMsgTemplateByDeviceId(msgTemplateDto.getDeviceId());
    if (retMsgTemplate != null && !retMsgTemplate.getId().equals(msgTemplateDto.getId())) {
      CheckParaUtils.printLogAndThrowException(
          logger, String.format("设备ID[%s]已存在", msgTemplateDto.getDeviceId()));
    }

    // 记录日志
    String logTitle = "修改消息模板：【" + JSONObject.toJSONString(msgTemplateDto) + "】";
    BdpLogUtil.log("消息模板管理", logTitle, PlatformConstant.OpType.update);

    // step3:更新
    updateByPrimaryKeySelective(msgTemplateDto);
  }

  /**
   * 删除消息模板
   *
   * @param msgTemplateDto
   * @throws Exception
   */
  public void deleteMsgTemplateByIds(MsgTemplateDto msgTemplateDto) {
    // step1:参数合法性检查
    CheckParaUtils.checkObjectValidity(msgTemplateDto, logger, "参数为null");
    CheckParaUtils.checkStringValidity(msgTemplateDto.getId(), logger, "参数[id]不能为空");

    // step2:遍历id，删除消息模板
    String ids = msgTemplateDto.getId();
    String[] idArray = ids.split(Constants.COMMA);
    for (String currId : idArray) {

      // 记录日志
      MsgTemplateDto templateDto = selectByPrimaryKey(currId);
      BdpLogUtil.log4Delete(templateDto);

      // 删除数据库模板记录
      deleteByPrimaryKey(currId);
    }
  }

  /**
   * 分页查询
   *
   * @param sort
   * @param deviceName
   * @param pageNo
   * @param pageSize
   * @return
   */
  public QueryRespBean<MsgTemplateDto> getMsgTemplateList(
      Integer sort, String deviceName, String projectId, Integer pageNo, Integer pageSize) {
    // step1:参数合法性检查
    if (sort == null) {
      CheckParaUtils.printLogAndThrowException(logger, "参数[sort]为null");
    }
    if (sort < DcsConstants.ORDERED_BY_MODIFIED_TIME_DESC
        || sort > DcsConstants.ORDERED_BY_TEMPLATE_NAME_DESC) {
      CheckParaUtils.printLogAndThrowException(logger, String.format("参数sort[%s]不合法", sort));
    }
    if (pageNo <= 0 || pageSize <= 0) {
      CheckParaUtils.printLogAndThrowException(
          logger, String.format("参数pageNo/pageSize[%s,%s]不合法", pageNo, pageSize));
    }

    // step2:构建排序参数
    QueryRespBean<MsgTemplateDto> queryRespBean = new QueryRespBean<>();
    com.github.pagehelper.PageHelper.startPage(pageNo, pageSize);
    // 排序，1:按修改时间倒序、2:按修改时间升序、3:按模板名称升序、4:按模板名称倒序
    String orderField = DcsConstants.LAST_UPDATE_DATE;
    String orderType = DcsConstants.DESC;
    if (DcsConstants.ORDERED_BY_MODIFIED_TIME_DESC == sort) {
      orderField = DcsConstants.LAST_UPDATE_DATE;
      orderType = DcsConstants.DESC;
    } else if (DcsConstants.ORDERED_BY_MODIFIED_TIME_ASC == sort) {
      orderField = DcsConstants.LAST_UPDATE_DATE;
      orderType = DcsConstants.ASC;
    } else if (DcsConstants.ORDERED_BY_TEMPLATE_NAME_ASC == sort) {
      orderField = DcsConstants.ORDERED_BY_TEMPLATE_NAME;
      orderType = DcsConstants.ASC;
    } else if (DcsConstants.ORDERED_BY_TEMPLATE_NAME_DESC == sort) {
      orderField = DcsConstants.ORDERED_BY_TEMPLATE_NAME;
      orderType = DcsConstants.DESC;
    }

    // step3:查表
    Page<MsgTemplateDto> templateList =
        this.msgTemplateDao.getMsgTemplateList(deviceName, orderField, orderType, projectId);
    valueConvert(templateList);
    queryRespBean.setResult(templateList);
    BdpLogUtil.log4Query(queryRespBean);
    return queryRespBean;
  }

  private void valueConvert(List<MsgTemplateDto> templateList) {
    // 循环组装请求数据
    Map<String, Set<String>> convertFormData = new HashMap<>();
    if (CollectionUtils.isNotEmpty(templateList)) {
      for (MsgTemplateDto msgTemplate : templateList) {
        BusinessUtil.createConvertSet(convertFormData, Constants.BDP_DATA_SECRET_LEVEL_KEY, msgTemplate.getSecretLevel());
      }
      if (convertFormData.size() > 0) {
        // 获取请求结果
        Map<String, Map<String, String>> convertResultData = convertColumnClient.replace(convertFormData);
        for (MsgTemplateDto msgTemplate : templateList) {
          msgTemplate.setSecretLevelName(BusinessUtil.convertFormat(
                  convertResultData, Constants.BDP_DATA_SECRET_LEVEL_KEY, msgTemplate.getSecretLevel()));
        }
      }
    }
  }

  /**
   * 新增消息模板测量参数
   *
   * @param msgTemplateDto
   * @throws Exception
   */
  public void addMsgTemplateParas(MsgTemplateDto msgTemplateDto) {
    // step1:参数合法性检查
    CheckParaUtils.checkObjectValidity(msgTemplateDto, logger, "参数为null");
    CheckParaUtils.checkStringValidity(msgTemplateDto.getId(), logger, "参数[id]不能为空");
    CheckParaUtils.checkObjectValidity(
        msgTemplateDto.getMeasureParaDtoList(), logger, "参数[measureParaDtoList]不能为空");

    // step2:检查消息模板是否存在
    MsgTemplateDto msgTemplateDtoQuery = selectByPrimaryKey(msgTemplateDto.getId());
    CheckParaUtils.checkObjectValidity(
        msgTemplateDtoQuery, logger, String.format("消息模板[%s]不存在", msgTemplateDto.getId()));

    // step3:检查本次新增参数是否合法
    List<MeasureParaDto> measureParaDtoList = msgTemplateDto.getMeasureParaDtoList();
    for (MeasureParaDto measureParaDto : measureParaDtoList) {
      CheckParaUtils.checkObjectValidity(measureParaDto, logger, "参数为null");
      CheckParaUtils.checkStringValidity(measureParaDto.getName(), logger, "参数[name]不能为空");
      CheckParaUtils.checkObjectValidity(measureParaDto.getType(), logger, "参数[type]不能为空");
    }

    // step4:解析本次新增测量参数，检查是否有重复值
    HashSet<MeasureParaDto> paraHashSet = new HashSet<>(measureParaDtoList);
    if (paraHashSet.size() != measureParaDtoList.size()) {
      CheckParaUtils.printLogAndThrowException(logger, "消息模板参数[paras]中存在重复值");
    }

    // 记录日志
    BdpLogUtil.log4Update(msgTemplateDto, msgTemplateDtoQuery);

    // step5:本次新增测量参数是否与模板中现有参数重复，如果重复则抛异常
    String currParas = msgTemplateDtoQuery.getParas();
    List<MeasureParaDto> currMeasureParaList = null;
    if (StringUtils.isEmpty(currParas)) {
      // step5-1:当前消息模板中没有测量参数
      // 设置参数的主键ID
      for (MeasureParaDto para : measureParaDtoList) {
        para.setId(ComUtil.getId());
        para.setDeviceId(msgTemplateDtoQuery.getDeviceId());
      }

      String newParas = JSONObject.toJSONString(measureParaDtoList);
      msgTemplateDtoQuery.setParas(newParas);
    } else {
      // step5-2:遍历新增参数，判断是否与现有参数重复
      currMeasureParaList = JSONUtils.toList(currParas, MeasureParaDto.class);
      for (MeasureParaDto para : measureParaDtoList) {
        if (currMeasureParaList.contains(para)) {
          CheckParaUtils.printLogAndThrowException(
              logger, String.format("消息模板参数[%s]与现有测量参数重复", para.getName()));
        }

        para.setId(ComUtil.getId());
        para.setDeviceId(msgTemplateDtoQuery.getDeviceId());
      }

      currMeasureParaList.addAll(measureParaDtoList);
      String newParas = JSONObject.toJSONString(currMeasureParaList);
      msgTemplateDtoQuery.setParas(newParas);
    }

    // step6:构造测量参数列表，持久化
    updateByPrimaryKeySelective(msgTemplateDtoQuery);

    String logTitle = "新增消息模板参数：【" + JSONObject.toJSONString(measureParaDtoList) + "】";
    BdpLogUtil.log("消息模板管理", logTitle, PlatformConstant.OpType.insert);
  }

  /**
   * 修改消息模板测量参数
   *
   * @param msgTemplateDto
   * @throws Exception 注意：入参modfiedMeasureParaDto.paras包含所有参数（待修改、未修改）
   */
  public void updateMsgTemplateParas(MsgTemplateDto msgTemplateDto) {
    // step1:参数合法性检查
    CheckParaUtils.checkObjectValidity(msgTemplateDto, logger, "参数为null");
    CheckParaUtils.checkStringValidity(msgTemplateDto.getId(), logger, "参数[id]不能为空");
    CheckParaUtils.checkObjectValidity(
        msgTemplateDto.getMeasureParaDtoList(), logger, "参数[measureParaDtoList]不能为空");

    // step2:检查消息模板是否存在
    MsgTemplateDto msgTemplateDtoQuery = selectByPrimaryKey(msgTemplateDto.getId());
    CheckParaUtils.checkObjectValidity(
        msgTemplateDtoQuery, logger, String.format("消息模板[%s]不存在", msgTemplateDto.getId()));

    // step3:检查本次新增参数是否合法
    List<MeasureParaDto> measureParaDtoList = msgTemplateDto.getMeasureParaDtoList();
    for (MeasureParaDto measureParaDto : measureParaDtoList) {
      CheckParaUtils.checkObjectValidity(measureParaDto, logger, "参数为null");
    }

    // step4:解析本次新增测量参数，检查是否有重复值
    HashSet<MeasureParaDto> paraHashSet = new HashSet<>(measureParaDtoList);
    if (paraHashSet.size() != measureParaDtoList.size()) {
      CheckParaUtils.printLogAndThrowException(logger, "消息模板参数[paras]中存在重复值");
    }

    // 记录日志
    BdpLogUtil.log4Update(msgTemplateDto, msgTemplateDtoQuery);

    // step5:本次修改的测量参数是否与模板中现有参数重复，如果重复则抛异常
    String currParas = msgTemplateDtoQuery.getParas();
    List<MeasureParaDto> currMeasureParaList = JSONUtils.toList(currParas, MeasureParaDto.class);
    if (StringUtils.isEmpty(currParas)) {
      // step5-1:当前消息模板中没有测量参数
      // 设置参数的主键ID
      for (MeasureParaDto para : measureParaDtoList) {
        para.setId(ComUtil.getId());
        para.setDeviceId(msgTemplateDtoQuery.getDeviceId());
      }

      String newParas = JSONObject.toJSONString(measureParaDtoList);
      msgTemplateDtoQuery.setParas(newParas);
    } else {
      // step5-2:遍历新增参数，判断是否与现有参数重复
      for (MeasureParaDto modPara : measureParaDtoList) {
        // 本次修改的参数不得与模板中现有参数重复（参数名称）
        // 待修改的测量参数必须在消息模板中存在（主键id相同）
        int cnt = 0;
        for (MeasureParaDto currPara : currMeasureParaList) {
          if (currPara.equals(modPara)) {
            cnt++;
          }
        }
        if (cnt > 1) {
          CheckParaUtils.printLogAndThrowException(
              logger,
              String.format("消息模板参数[%s,%s}]与其他参数重复", modPara.getName(), modPara.getDeviceId()));
        }

        // 待修改的测量参数必须在消息模板中存在（主键id相同）
        boolean isFind = false;
        for (MeasureParaDto currPara : currMeasureParaList) {
          if (currPara.getId().equals(modPara.getId())) {
            isFind = true;
            currPara.setName(modPara.getName());
            currPara.setType(modPara.getType());
            currPara.setRemark(modPara.getRemark());
            currPara.setPrefix(modPara.getPrefix());
          }
        }
        if (!isFind) {
          CheckParaUtils.printLogAndThrowException(
              logger,
              String.format("消息模板参数[%s,%s]之前不在设备中，不允许修改", modPara.getName(), modPara.getId()));
        }
      }

      String newParas = JSONObject.toJSONString(currMeasureParaList);
      msgTemplateDtoQuery.setParas(newParas);
    }

    // step6:构造测量参数列表，持久化
    updateByPrimaryKeySelective(msgTemplateDtoQuery);

    String logTitle = "修改消息模板参数：【" + JSONObject.toJSONString(measureParaDtoList) + "】";
    BdpLogUtil.log("消息模板管理", logTitle, PlatformConstant.OpType.update);
  }

  /**
   * 删除消息模板测量参数
   *
   * @param msgTemplateDto
   * @throws Exception
   */
  public void deleteMsgTemplateParas(MsgTemplateDto msgTemplateDto) {
    // step1:参数合法性检查
    CheckParaUtils.checkObjectValidity(msgTemplateDto, logger, "参数为null");
    CheckParaUtils.checkStringValidity(msgTemplateDto.getId(), logger, "参数[id]不能为空");
    CheckParaUtils.checkObjectValidity(
        msgTemplateDto.getMeasureParaDtoList(), logger, "参数[measureParaDtoList]不能为空");

    // step2:检查消息模板是否存在
    MsgTemplateDto msgTemplateDtoQuery = selectByPrimaryKey(msgTemplateDto.getId());
    CheckParaUtils.checkObjectValidity(
        msgTemplateDtoQuery, logger, String.format("消息模板[%s]不存在", msgTemplateDto.getId()));

    // step3:删除测量参数
    String currParas = msgTemplateDtoQuery.getParas();
    CheckParaUtils.checkStringValidity(currParas, logger, "消息模板中参数不存在");

    // 记录日志
    BdpLogUtil.log4Update(msgTemplateDto, msgTemplateDtoQuery);

    // step4:保证待删除的消息参数都在当前消息模板中
    List<MeasureParaDto> currMeasureParaList = JSONUtils.toList(currParas, MeasureParaDto.class);
    for (MeasureParaDto delPara : msgTemplateDto.getMeasureParaDtoList()) {
      boolean isFind = false;
      Iterator<MeasureParaDto> it = currMeasureParaList.iterator();
      while (it.hasNext()) {
        MeasureParaDto currPara = it.next();
        if (currPara.getId().equals(delPara.getId())) {
          it.remove();
          isFind = true;
        }
      }

      // 所有待删除的测量参数都应该在当前消息模板中，如果不在则抛异常
      if (!isFind) {
        String message = String.format("待删除的参数[%s]不存在", delPara.getId());
        CheckParaUtils.printLogAndThrowException(logger, message);
      }
    }

    // step5:构造测量参数列表，持久化
    String newParas = JSONObject.toJSONString(currMeasureParaList);
    msgTemplateDtoQuery.setParas(newParas);
    updateByPrimaryKey(msgTemplateDtoQuery);

    String logTitle = "删除消息模板参数：【" + JSONObject.toJSONString(msgTemplateDto) + "】";
    BdpLogUtil.log("消息模板管理", logTitle, PlatformConstant.OpType.delete);
  }

  /**
   * 获取指定消息模板Id的测量参数列表
   *
   * @param id
   * @param paraName
   * @return
   */
  public List<MeasureParaDto> getParasByTemplateId(String id, String paraName) {
    // step1:参数合法性检查
    CheckParaUtils.checkStringValidity(id, logger, "参数[id]不能为空");

    // step2:检查消息模板是否存在
    MsgTemplateDto msgTemplateDtoQuery = selectByPrimaryKey(id);
    CheckParaUtils.checkObjectValidity(
        msgTemplateDtoQuery, logger, String.format("消息模板[%s]不存在", id));

    // step3:返回查询结果
    String paraString = msgTemplateDtoQuery.getParas();
    if (paraString == null) {
      return new ArrayList<>();
    }
    // 消息模板中没有任何参数，返回空表
    List<MeasureParaDto> currMeasureParaList = JSONUtils.toList(paraString, MeasureParaDto.class);
    if (currMeasureParaList == null) {
      return new ArrayList<>();
    }

    // step4:根据paraName过滤结果
    List<MeasureParaDto> retList = null;
    if (!StringUtils.isEmpty(paraName)) {
      retList = new ArrayList<>();
      for (MeasureParaDto paraDto : currMeasureParaList) {
        if (paraDto.getName().toUpperCase().contains(paraName.toUpperCase())) {
          retList.add(paraDto);
        }
      }
    } else {
      retList = currMeasureParaList;
    }

    Collections.reverse(retList);

    return retList;
  }

  /**
   * 导入消息模板文件
   *
   * @param msgTemplateDto
   * @return
   * @throws Exception
   */
  public List<MsgTemplateDto> upload(MsgTemplateDto msgTemplateDto) throws Exception {
    // step1:合法性检查
    CheckParaUtils.checkObjectValidity(msgTemplateDto, logger, "参数为null");
    CheckParaUtils.checkObjectValidity(msgTemplateDto.getFile(), logger, "参数[file]不能为空");

    // step2:解析deviceInfos
    MultipartFile file = msgTemplateDto.getFile();
    String fileName = file.getResource().getFilename();
    CheckParaUtils.checkStringValidity(fileName, logger, "参数[file]中filename字段不能为空");
    String projectId = msgTemplateDto.getProjectId();

    logger.info("开始上传模板文件[{}}]...", fileName);

    InputStream inputStream = file.getInputStream();
    CheckParaUtils.checkObjectValidity(inputStream, logger, "参数[file]中inputStream字段不能为空");
    List<MsgTemplateDto> devices = MsgTemplateExcelUtils.parseDevices(fileName, file.getInputStream());

    // step3:解析结果持久化;(注意：templateId相同会直接覆盖掉现有值)
    for (MsgTemplateDto tmpTemplateDto : devices) {
      MsgTemplateDto queryRet = this.mapper.getMsgTemplateByDeviceId(tmpTemplateDto.getDeviceId());

      // 记录日志
      BdpLogUtil.log4Update(msgTemplateDto, queryRet);

      if (queryRet != null) {
        // step3.1:消息模板（templateId已存在），更新字段
        // 注意1：此处不能直接修改tmpTemplateDto，因为这个值要返给VUE前端用于展示
        // 注意2：此处要覆盖queryRet中部分字段
        queryRet.setDeviceId(tmpTemplateDto.getDeviceId());
        queryRet.setDeviceName(tmpTemplateDto.getDeviceName());
        queryRet.setRemark(tmpTemplateDto.getRemark());
        queryRet.setDeviceTypeId(tmpTemplateDto.getDeviceTypeId());
        queryRet.setDeviceTypeName(tmpTemplateDto.getDeviceTypeName());
        queryRet.setAreaId(tmpTemplateDto.getAreaId());
        queryRet.setAreaName(tmpTemplateDto.getAreaName());
        queryRet.setAssetId(tmpTemplateDto.getAssetId());
        queryRet.setAssetName(tmpTemplateDto.getAssetName());
        queryRet.setCustomerId(tmpTemplateDto.getCustomerId());
        queryRet.setCustomerName(tmpTemplateDto.getCustomerName());
        queryRet.setParas(tmpTemplateDto.getParas());
        queryRet.setProjectId(projectId);

        updateByPrimaryKey(queryRet);
      } else {
        // 记录日志
        tmpTemplateDto.setProjectId(projectId);
        BdpLogUtil.log4Insert(tmpTemplateDto);

        // step3.2:消息模板（templateID不存在），直接插入
        insert(tmpTemplateDto);
      }
    }

    logger.info("上传模板文件[{}]成功", fileName);

    return devices;
  }

  /**
   * 下载模板示例文件
   *
   * @param filePath
   * @param response
   * @throws Exception
   */
  public void downloadFile(String filePath, HttpServletResponse response) {
    InputStream inputStream = null;
    OutputStream outputStream = null;

    try {
      // step1:设置消息头
      // 设置文件ContentType类型，这样设置，会自动判断下载文件类型
      response.setContentType("multipart/form-data");
      // 设置文件头：最后一个参数是设置下载文件名
      String fileName = URLEncoder.encode(DcsConstants.MSG_TEMPLATE_EXAMPLE_FILE_PATH, "utf-8");
      response.setHeader(
          "Content-Disposition",
          "attachment;filename=" + DcsConstants.MSG_TEMPLATE_EXAMPLE_FILE_PATH);

      // step2：返回数据流
      logger.info("下载的文件名称为：{}", fileName);
      inputStream =
          this.getClass()
              .getClassLoader()
              .getResourceAsStream(DcsConstants.MSG_TEMPLATE_EXAMPLE_FILE_PATH);
      outputStream = response.getOutputStream();
      byte[] b = new byte[DcsConstants.MSG_TEMPLATE_EXAMPLE_FILE_WRITER_BUFFER_SIZE];
      int len;
      while ((len = inputStream.read(b)) > 0) {
        outputStream.write(b, 0, len);
      }

      outputStream.flush();
    } catch (Exception e) {
      logger.error("下载消息模板示例文件失败", e);
      throw new BusinessException(
          String.format("下载消息模板示例文件%s失败", DcsConstants.MSG_TEMPLATE_EXAMPLE_FILE_PATH));
    } finally {
      try {
        if (inputStream != null) {
          inputStream.close();
        }
        if (outputStream != null) {
          outputStream.close();
        }
      } catch (Exception e) {
        logger.error("下载消息模板示例文件失败", e);
      }
    }
  }

  /**
   * 判断设备ID是否重复
   *
   * @param deviceId
   * @return
   */
  private boolean isDeviceIdRepeated(String deviceId) {
    MsgTemplateDto msgTemplateDto = this.mapper.getMsgTemplateByDeviceId(deviceId);
    if (msgTemplateDto == null) {
      return false;
    }

    return true;
  }

  /**
   * 获取所有模板列表
   *
   * @param deviceName
   * @return
   */
  public List<MsgTemplateDto> getMsgTemplateList(String deviceName, String projectId) {
    return msgTemplateDao.selectListAll(deviceName, projectId);
  }
}
